# app/api/v1/services.py
from sqlalchemy.orm import Session
import logging
logger = logging.getLogger(__name__)

from app.map_planner.models import Warehouse1, Warehouse2
from app.map_planner.algorithm import TSP
from . import schemas
from app.core import Warehouse
from app.map_planner import MapBase

class Services:
    def __init__(self) -> None:
        self.tsp = TSP()
        self.map_base = MapBase()

    def update_pallet_by_loc(
            self, 
            db: Session, 
            wh_location: str,
            pallet_id: str
    ) -> list:
        """用库位坐标, 更新库位托盘号。

        Args:
            db: 数据库连接
            wh_location: 库位坐标 'wh,x,y' - '库区,层,列'
            pallet_id: 托盘号

        Returns:
            list: [True, location_info] or [False, "error message"]
        """
        # 禁用库位
        # Disable locations
        disable_locations = [
            "1,1,1", "1,2,1", "1,1,28", "1,2,28",
            "2,1,1", "2,2,1", "2,1,28", "2,2,28"
            ]
        if wh_location in disable_locations:
            logger.error(f"库位已禁用: {wh_location}")
            return [False, "库位已禁用"]
        
        # 获取库位信息
        # Get location info
        warehouse = self.map_base.split_location_by_loc(wh_location)["warehouse"]
        
        # 获取库位模型
        # Get location model
        if warehouse == 1:
            LocationModel = Warehouse1
        elif warehouse == 2:
            LocationModel = Warehouse2
        else:
            logger.error(f"查询库区号不存在: {warehouse}")
            return [False, "查询库区号不存在"]
        
        # 查询库位信息 匹配是否存在
        # Check if location exists
        location_info = db.query(LocationModel).filter(LocationModel.location == wh_location).first()
        if not location_info:
            logger.error(f"无库位信息: {wh_location}")
            return [False, "无库位信息"]
        
        # 写入库位托盘号
        # Update pallet ID and status
        db.query(LocationModel).filter(LocationModel.location == wh_location).update({
            LocationModel.pallet_id: pallet_id,
            LocationModel.status: Warehouse.CARGO.value
            })

        # 提交更改并刷新
        # Commit changes and refresh
        db.commit()
        db.refresh(location_info)
        logger.info(f"更新库位托盘号成功: {wh_location}")
        return [True, location_info]
    
    def delete_pallet_by_loc(
            self, 
            db: Session, 
            wh_location: str
            ) -> list:
        """用库位ID, 删除库位托盘号。

        Args:
            db: 数据库连接
            wh_location: 库位坐标 'wh,x,y' - '库区,层,列'

        Returns:
            list: [True, location_info] or [False, "error message"]
        """
        # 禁用库位
        # Disable locations
        disable_locations = [
            "1,1,1", "1,2,1", "1,1,28", "1,2,28",
            "2,1,1", "2,2,1", "2,1,28", "2,2,28"
            ]
        if wh_location in disable_locations:
            logger.error(f"库位已禁用: {wh_location}")
            return [False, "库位已禁用"]
        
        # 获取库位信息
        # Get location info
        warehouse = self.map_base.split_location_by_loc(wh_location)["warehouse"]
        
        # 获取库位模型
        # Get location model
        if warehouse == 1:
            LocationModel = Warehouse1
        elif warehouse == 2:
            LocationModel = Warehouse2
        else:
            logger.error(f"查询库区号不存在: {warehouse}")
            return [False, "查询库区号不存在"]
        
        # 查询库位信息 匹配是否存在
        # Check if location exists
        location_info = db.query(LocationModel).filter(LocationModel.location == wh_location).first()
        if not location_info:
            logger.error(f"无库位信息: {wh_location}")
            return [False, "无库位信息"]
        
        # 写入库位托盘号
        # Update pallet ID and status
        db.query(LocationModel).filter(LocationModel.location == wh_location).update({
            LocationModel.pallet_id: None, 
            LocationModel.status: Warehouse.FREE.value
            })
        
        # 提交更改并刷新
        # Commit changes and refresh
        db.commit()
        db.refresh(location_info)
        logger.info(f"删除库位托盘号成功: {wh_location}")
        return [True, location_info]

    def task_processing(
            self, 
            db: Session, 
            request: schemas.RequestMixTaskList
            ) -> list:
        """出库、入库、库内转移任务处理。
        
        Args:
            db: 数据库连接
            request: 请求体数据
        
        Returns:
            list: [True, resp_list] or [False, "error message"]
        """
        # 空任务列表
        # Empty task list
        resp_list = []

        # 堆垛机位置
        # Stacker position
        stacker_pos = request.stacker_location

        # 优化任务顺序
        # Optimize task order
        task_loc_list = [task.description[0].target_location for task in request.tasks]
        optimal_task_list = self.tsp.advanced_nearest_neighbor(stacker_pos, task_loc_list)
        tasks = sorted(request.tasks, key=lambda x: optimal_task_list.index(x.description[0].target_location))
        
        for task in tasks:
            task_no = task.task_no
            task_desc = task.description[0]
            task_type = task_desc.task_type
            start_gate_pos = task_desc.start_or_gate_location
            target_pos = task_desc.target_location

            # 入库
            if task_type == 0:
                logger.info(f"入库任务: {task_no}")
                stacker_to_gate_path = [1, stacker_pos, start_gate_pos]
                gate_to_target_path = [2, start_gate_pos, target_pos]
                resp_list.append({
                    "task_no": task_no,
                    "task_type": task_type,
                    "path_1": stacker_to_gate_path,
                    "path_2": gate_to_target_path,
                    "end_location": target_pos,
                })
                # 数据库更新
                self.update_pallet_by_loc(
                    db=db,
                    wh_location=target_pos,
                    pallet_id=task_no
                )
                # 堆垛机最终位置
                stacker_pos = target_pos
            
            # 出库
            elif task_type == 1:
                logger.info(f"出库任务: {task_no}")
                stacker_to_target_path = [1, stacker_pos, target_pos]
                target_to_gate_path = [2, target_pos, start_gate_pos]
                resp_list.append({
                    "task_no": task_no,
                    "task_type": task_type,
                    "path_1": stacker_to_target_path,
                    "path_2": target_to_gate_path,
                    "end_location": start_gate_pos,
                })
                # 数据库更新
                self.delete_pallet_by_loc(
                    db=db,
                    wh_location=target_pos
                )
                # 堆垛机最终位置
                stacker_pos = start_gate_pos

            # 库内移动
            elif task_type == 2:
                logger.info(f"库内转移任务: {task_no}")
                stacker_to_gate_path = [1, stacker_pos, start_gate_pos]
                gate_to_target_path = [2, start_gate_pos, target_pos]
                resp_list.append({
                    "task_no": task_no,
                    "task_type": task_type,
                    "path_1": stacker_to_gate_path,
                    "path_2": gate_to_target_path,
                    "end_location": target_pos,
                })
                # 数据库更新
                self.delete_pallet_by_loc(
                    db=db,
                    wh_location=start_gate_pos
                )
                self.update_pallet_by_loc(
                    db=db,
                    wh_location=target_pos,
                    pallet_id=task_no
                )
                # 堆垛机最终位置
                stacker_pos = target_pos

            else:
                logger.error(f"任务类型错误: {task_type}")
                return [False, "任务类型错误"]

        logger.info(f"处理任务成功")
        return [True, resp_list]